//*********************************************************
//
//    Copyright (c) Microsoft. All rights reserved.
//    This code is licensed under the Apache License, Version 2.0.
//    THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
//    ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
//    IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
//    PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************

using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Configuration;
using System.Drawing;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Security.Permissions;
using ManagementStudioServices.Interfaces;
using Microsoft.Research.ScientificWorkflow.ManagementStudioModels;
using Microsoft.Research.ScientificWorkflow.TridentComposer;
using Microsoft.Research.ScientificWorkflow.TridentUtilities;
using Microsoft.Research.ScientificWorkflow.TridentUtilities.Properties;
using Microsoft.Research.DataLayer;
using Microsoft.Research.eResearch.Common.Linq;
using TridentAPI;

namespace ManagementStudioServices
{
    /// <summary>
    /// Service which connects to the registry for registry based operations.
    /// </summary>
    public class RegistryManagerService : IRegistryManagerService
    {
        #region Private variables

        /// <summary>
        /// This is used to access registry connection.
        /// </summary>
        private Connection registryConnection;

        /// <summary>
        /// System user name.
        /// </summary>
        private const string SystemUserName = "System";

        /// <summary>
        /// The system user object.
        /// </summary>
        private User systemUserObject;

        /// <summary>
        /// Holds the current user.
        /// </summary>
        private User currentUser;

        #endregion

        #region Constructor

        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="registryConnection">The registry connection.</param>
        public RegistryManagerService(Connection registryConnection)
        {
            this.registryConnection = registryConnection;
            this.systemUserObject = this.GetSystemUser();
            this.currentUser = TridentAuthentication.LoggedInUser;
        }

        #endregion Constructor

        #region IRegistryManagerService Members

        /// <summary>
        /// Gets the registry connection.
        /// </summary>
        /// <value>The registry connection.</value>
        public Connection RegistryConnection
        {
            get
            {
                return this.registryConnection;
            }
        }

        /// <summary>
        /// Gets the name of the user.
        /// </summary>
        /// <value>The name of the user.</value>
        public string UserName
        {
            get
            {
                return this.systemUserObject.Name;

            }
        }

        /// <summary>
        /// Get the activity category root.
        /// </summary>
        /// <returns>
        /// Activity root category.
        /// </returns>
        public Namespace GetActivityCategories()
        {
            Namespace activityRoot = null;
            try
            {
                activityRoot = this.systemUserObject.ActivityRoot;
                if (activityRoot == null)
                {
                    throw new ArgumentException("Activity root is null");
                }
                else
                {
                    activityRoot.Refresh();
                }
            }
            catch (Exception ex)
            {
                TridentErrorHandler.ProcessKnownExceptionsInBusinessLogic(ex);
                TridentErrorHandler.HandleAndThrowBusinessLogicException(ex, TridentErrorConstants.ErrorNumber1000000029, ex.Message);
            }

            return activityRoot;
        }

        /// <summary>
        /// Get the workflow category root.
        /// </summary>
        /// <returns>
        /// Workflow root category.
        /// </returns>
        public Namespace GetWorkflowCategories()
        {
            Namespace wfRoot = null;
            try
            {
                wfRoot = this.systemUserObject.WorkflowRoot;
                if (null == wfRoot)
                {
                    throw new ArgumentException("Workflow root is null");
                }
                else
                {
                    wfRoot.Refresh();
                }
            }
            catch (Exception ex)
            {
                TridentErrorHandler.ProcessKnownExceptionsInBusinessLogic(ex);
                TridentErrorHandler.HandleAndThrowBusinessLogicException(ex, TridentErrorConstants.ErrorNumber1000000030, ex.Message);
            }

            return wfRoot;
        }

        /// <summary>
        /// 
        /// </summary>
        public bool DeleteWorkflowCategory(CategoryViewModel modelToDelete, CategoryViewModel moveToModel)
        {
            bool deleteSuccess = true;
            if (null == modelToDelete)
            {
                deleteSuccess = false;
            }
            else
            {
                try
                {
                    Namespace categoryToDelete = Namespace.Load(modelToDelete.Id, this.registryConnection);
                    if (null == categoryToDelete)
                    {
                        deleteSuccess = false;
                    }
                    else
                    {
                        if (moveToModel != null)
                        {
                            Namespace moveToCategory = Namespace.Load(moveToModel.Id, this.registryConnection);
                            if (null == moveToCategory)
                            {
                                deleteSuccess = false;
                            }
                            else
                            {
                                this.CascadeMoveActivities(categoryToDelete, moveToCategory);
                            }
                        }

                        if (deleteSuccess)
                        {
                            categoryToDelete.CascadeDelete();
                            CategoryViewModel deletedCategoryParentModel = modelToDelete.Parent as CategoryViewModel;
                            if (deletedCategoryParentModel != null)
                            {
                                deleteSuccess = deletedCategoryParentModel.RemoveChildModel(modelToDelete);
                            }
                        }
                    }
                }
                catch (RecordNotFoundException ex)
                {
                    deleteSuccess = false;
                    TridentErrorHandler.HandleAndThrowBusinessLogicException(ex, TridentErrorConstants.ErrorNumber1000000026, ex.Message);
                }
                catch (InvalidOperationException ex)
                {
                    deleteSuccess = false;
                    TridentErrorHandler.HandleAndThrowBusinessLogicException(ex, TridentErrorConstants.ErrorNumber1000000027, ex.Message);
                }
                catch (Exception ex)
                {
                    deleteSuccess = false;
                    TridentErrorHandler.ProcessKnownExceptionsInBusinessLogic(ex);
                    TridentErrorHandler.HandleAndThrowBusinessLogicException(ex, TridentErrorConstants.ErrorNumber1000000028, ex.Message);
                }
            }

            return deleteSuccess;
        }

        /// <summary>
        /// Saves the category to the registry.
        /// </summary>
        /// <param name="model">
        /// The category model.
        /// </param>
        /// <returns>
        /// True if save succeeds, false otherwise.
        /// </returns>
        public Namespace SaveCategory(CategoryViewModel model)
        {
            Namespace savedNamespace = null;
            if (this.registryConnection != null && model != null)
            {
                Namespace categoryNamespace = null;
                try
                {
                    if (!model.Id.Equals(Guid.Empty))
                    {
                        categoryNamespace = Namespace.Load(model.Id, this.registryConnection);
                    }
                }
                catch (RecordNotFoundException ex)
                {
                    TridentErrorHandler.HandleUIException(ex);
                }

                if (null == categoryNamespace)
                {
                    savedNamespace = this.CreateCategoryFromModel(model);
                }
                else
                {
                    savedNamespace = this.UpdateNamespace(model, categoryNamespace);
                }
            }

            return savedNamespace;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public bool SaveUser(UserViewModel model, out User user)
        {
            try
            {
                if (model != null && this.registryConnection != null)
                {
                    if (model.Name.ToUpperInvariant().Equals(Constants.SystemUserName.ToUpperInvariant())
                        || model.Name.ToUpperInvariant().Equals(Constants.AnonymousUserName.ToUpperInvariant()))
                    {
                        throw new TridentCustomException(
                            string.Format(CultureInfo.CurrentCulture, "{0}{2}{1}", ManagementStudioResourceManager.GetString("UserNameExistsError"),
                            ManagementStudioResourceManager.GetString("UsedBySystemError"), Environment.NewLine));
                    }

                    if (User.CommonSearches.UserExistInRegistry(model.Id, model.Name, this.registryConnection))
                    {
                        throw new TridentCustomException(ManagementStudioResourceManager.GetString("UserNameExistsError"));
                    }

                    if (model.Id == Guid.Empty)
                    {
                        // Create a new User
                        user = User.Create(model.Name.Trim(), this.registryConnection);
                        if (!string.IsNullOrEmpty(model.Description))
                        {
                            user.Description = model.Description.Trim();
                        }

                        user.IsBuiltin = false;
                        user.Enabled = model.Status;
                        user.Save();
                    }
                    else
                    {
                        user = User.Load(model.Id, this.registryConnection);
                        user.Name = model.Name.Trim();
                        // Check if the user is having any Administrator role or group in the current User Model
                        CredentialRoleModel adminrole = model.Roles.FirstOrDefault(p => p.RoleSelected && p.RoleName == SystemRoleType.TridentAdministrators.ToString());
                        CredentialGroupModel admingroup = model.Groups.FirstOrDefault(p => p.IsSelected && p.GroupName == SystemBuiltinRoleType.Administrators.ToString());
                        if (adminrole == null && admingroup == null)
                        {
                            // If the current User Model is not having any admin roles, Check whether the registry is having any active  user having administrator group / role  
                            if (User.CommonSearches.GetAllAdminUsersCount(this.registryConnection, model.Id) == 0)
                            {
                                throw new TridentCustomException(ManagementStudioResourceManager.GetString("ErrorIFNOAdminIsActive"));
                            }
                        }
                        else if (User.CommonSearches.GetAllAdminUsersCount(this.registryConnection, model.Id) == 0 && !model.Status)
                        {
                            throw new TridentCustomException(ManagementStudioResourceManager.GetString("ErrorIFNOAdminIsActive"));
                        }

                        user.Enabled = model.Status;
                        if (!string.IsNullOrEmpty(model.Description))
                        {
                            user.Description = model.Description.Trim();
                        }

                        user.Groups.Clear();
                        user.Save();
                    }

                    TridentAuthentication.CreateMyWorkflowCategory(user, this.registryConnection);

                    this.SaveUserCredentials(user, model);
                    this.SaveUserGroups(user, model);
                    this.SaveUserRoles(user, model);

                    user.Refresh();
                    if (!user.IsBuiltin)
                    {
                        // This check has to be removed when Remove Roles feature is implemented.
                        this.GrantRegistryAccess(user);
                    }

                    return true;
                }
                else
                {
                    user = null;
                    return false;
                }
            }
            catch (TridentCustomException)
            {
                throw;
            }
            catch (RecordNotFoundException)
            {
                throw new TridentCustomException(ManagementStudio.UserRetrieveError);
            }
            catch (Exception ex)
            {
                TridentErrorHandler.ProcessKnownExceptionsInBusinessLogic(ex);
                TridentErrorHandler.HandleAndThrowBusinessLogicException(ex, 0, "Error while saving the User");
                throw new TridentCustomException("Error while saving the User");

            }
        }

        /// <summary>
        /// Grants the registry access.
        /// </summary>
        /// <param name="securityPrincipal">The security principal.</param>
        private void GrantRegistryAccess(ISecurityPrincipal securityPrincipal)
        {
            try
            {
                this.registryConnection.StorageSecurity.GrantDirectAccess(securityPrincipal, StorageRole.Administrator);
            }
            catch (BackendStorageException ex)
            {
                TridentErrorHandler.HandleAndThrowBusinessLogicException(
                    ex,
                    TridentErrorConstants.ErrorNumber1000000076,
                    string.Format(CultureInfo.CurrentCulture, ManagementStudio.UserGrantAccessManually, (securityPrincipal as INamedObject).Name));
            }
        }

        private void SaveGroupCredentials(Group group, GroupViewModel model)
        {

            Collection<ISecurityCredential> removeCredentialList = new Collection<ISecurityCredential>();

            // Loop the Registry Object and find the removed Credentials and add it to the RemoveCredential List
            foreach (ISecurityCredential credential in ((ISecurityPrincipal)group).Credentials)
            {
                LogOnCredentialModel savedCredential = model.Credentials.FirstOrDefault(p => p.CredentialName.Equals(credential.Credential));
                if (savedCredential == null)
                {
                    removeCredentialList.Add(credential);
                }
            }

            // Loop the LoginCredentialModel and find the newly added Model to the registry
            foreach (LogOnCredentialModel credentialModel in model.Credentials)
            {
                ISecurityCredential newCredential = ((ISecurityPrincipal)group).Credentials.FirstOrDefault(p => p.Credential.Equals(credentialModel.CredentialName));
                if (newCredential == null)
                {
                    GroupCredential groupCredential = GroupCredential.Create(credentialModel.CredentialName, CredentialType.Windows, group, this.registryConnection);
                    groupCredential.DisplayName = credentialModel.CredentialDisplayName;
                    groupCredential.Save();
                }
            }


            // Loop the RemoveCredential and remove from the registry.
            foreach (ISecurityCredential credentiial in removeCredentialList)
            {
                GroupCredential groupCredential = credentiial as GroupCredential;
                if (groupCredential != null)
                {
                    groupCredential.Delete();
                }
            }

        }

        private void SaveUserCredentials(User user, UserViewModel model)
        {

            Collection<ISecurityCredential> removeCredentialList = new Collection<ISecurityCredential>();


            // Loop the Registry Object and find the removed Credentials and add it to the RemoveCredential List
            foreach (ISecurityCredential credential in ((ISecurityPrincipal)user).Credentials)
            {
                LogOnCredentialModel savedCredential = model.Credentials.FirstOrDefault(p => p.CredentialName.Equals(credential.Credential));
                if (savedCredential == null)
                {
                    removeCredentialList.Add(credential);
                }
            }

            // Loop the LoginCredentialModel and find the newly added Model to the registry
            foreach (LogOnCredentialModel credentialModel in model.Credentials)
            {
                ISecurityCredential newCredential = ((ISecurityPrincipal)user).Credentials.FirstOrDefault(p => p.Credential.Equals(credentialModel.CredentialName));
                if (newCredential == null)
                {
                    UserCredential userCredential = UserCredential.Create(credentialModel.CredentialName, CredentialType.Windows, user, this.registryConnection);
                    userCredential.DisplayName = credentialModel.CredentialDisplayName;
                    userCredential.Save();
                }
            }


            // Loop the RemoveCredential and remove from the registry.
            foreach (ISecurityCredential credentiial in removeCredentialList)
            {

                UserCredential userCredentiial = credentiial as UserCredential;
                if (userCredentiial != null)
                {
                    userCredentiial.Delete();
                }
            }

        }

        private void SaveUserGroups(User user, UserViewModel model)
        {
            Collection<CredentialGroupModel> activeGroupsModel = new Collection<CredentialGroupModel>();
            foreach (CredentialGroupModel groupModel in model.Groups)
            {
                if (groupModel.IsSelected)
                {
                    activeGroupsModel.Add(groupModel);
                }
            }

            Collection<Group> removeGroup = new Collection<Group>();

            foreach (Group group in user.Groups)
            {
                CredentialGroupModel savedGroupModel = activeGroupsModel.FirstOrDefault(p => p.GroupName.Equals(group.Name));
                if (savedGroupModel != null)
                {
                    activeGroupsModel.Remove(savedGroupModel);
                }
                else
                {
                    removeGroup.Add(group);
                }
            }

            // Remove the Un checked group
            foreach (Group group in removeGroup)
            {
                user.Groups.Remove(group);
            }


            foreach (CredentialGroupModel groupModel in activeGroupsModel)
            {
                Group group = null;
                try
                {
                    group = Group.Load(groupModel.GroupName, this.registryConnection);
                }
                catch (RecordNotFoundException)
                {

                }

                if (group != null)
                {
                    user.Groups.Add(group);
                    user.Refresh();
                }
            }

        }

        private void SaveUserRoles(User user, UserViewModel model)
        {
            // Remove all roles
            user.SystemRoles.ForEach(p => p.Delete());
            List<CredentialRoleModel> rolesModel = (from n in model.Roles where n.RoleSelected == true select n).ToList();
            SystemPolicy policy = SystemPolicy.Get(this.registryConnection);
            foreach (CredentialRoleModel role in rolesModel)
            {
                if (role.RoleName.Equals(SystemRoleType.TridentUsers.ToString()))
                {
                    policy.TridentUsers.Add(user);
                }

                else if (role.RoleName.Equals(SystemRoleType.TridentAdministrators.ToString()))
                {
                    policy.TridentAdministrators.Add(user);
                }
                else if (role.RoleName.Equals(SystemRoleType.TridentGuests.ToString()))
                {
                    policy.TridentGuests.Add(user);
                }
                else if (role.RoleName.ToString().Equals(SystemRoleType.TridentServices.ToString()))
                {
                    policy.TridentServices.Add(user);
                }
            }

            policy.Refresh();
        }

        private void SaveGroupRoles(Group group, GroupViewModel model)
        {
            // Remove all roles
            group.SystemRoles.ForEach(p => p.Delete());
            List<CredentialRoleModel> rolesModel = (from n in model.Roles where n.RoleSelected == true select n).ToList();
            SystemPolicy policy = SystemPolicy.Get(this.registryConnection);
            foreach (CredentialRoleModel role in rolesModel)
            {
                if (role.RoleName.Equals(SystemRoleType.TridentUsers.ToString()))
                {
                    policy.TridentUsers.Add(group);
                }

                else if (role.RoleName.Equals(SystemRoleType.TridentAdministrators.ToString()))
                {
                    policy.TridentAdministrators.Add(group);
                }
                else if (role.RoleName.Equals(SystemRoleType.TridentGuests.ToString()))
                {
                    policy.TridentGuests.Add(group);
                }
                else if (role.RoleName.ToString().Equals(SystemRoleType.TridentServices.ToString()))
                {
                    policy.TridentServices.Add(group);
                }
            }

            policy.Refresh();
        }


        private void SaveGroupUsers(Group group, GroupViewModel model)
        {
            Collection<User> removeList = new Collection<User>();
            Collection<User> addList = new Collection<User>();
            foreach (User user in group.Users)
            {
                SearchUserModel userModel = model.Users.FirstOrDefault(p => p.UserName.Equals(user.Name));
                // Remove the User from the Model if its already present in the registry
                if (userModel == null)
                {
                    removeList.Add(user);
                }
            }

            foreach (SearchUserModel userModel in model.Users)
            {
                User user = group.Users.FirstOrDefault(p => p.Name.Equals(userModel.UserName));
                User addUser = null;
                // Remove the User from the Model if its already present in the registry
                if (user == null)
                {
                    try
                    {
                        addUser = User.Load(userModel.UserName, this.registryConnection);
                    }
                    catch (RecordNotFoundException)
                    {

                    }
                    if (addUser != null)
                    {
                        addList.Add(addUser);
                    }
                }
            }

            foreach (User user in removeList)
            {
                group.Users.Remove(user);
            }

            foreach (User user in addList)
            {
                group.Users.Add(user);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public bool SaveGroup(GroupViewModel model, out Group group)
        {
            try
            {
                if (model != null && this.registryConnection != null)
                {

                    if (model.Name.ToUpperInvariant().Equals(Constants.EVERYONEGROUP.ToUpperInvariant()))
                    {
                        throw new TridentCustomException(
                            string.Format(CultureInfo.CurrentCulture, "{0}{2}{1}", ManagementStudioResourceManager.GetString("GroupNameExistsError"),
                            ManagementStudioResourceManager.GetString("UsedBySystemError"), Environment.NewLine));
                    }

                    if (Group.CommonSearches.GroupExistInRegistry(model.Id, model.Name, this.registryConnection))
                    {
                        throw new TridentCustomException(ManagementStudioResourceManager.GetString("GroupNameExistsError"));
                    }


                    if (model.Id == Guid.Empty)
                    {
                        // Create a new User
                        group = Group.Create(model.Name.Trim(), this.registryConnection);
                        group.Enabled = model.Status;
                        if (!string.IsNullOrEmpty(model.Description))
                        {
                            group.Description = model.Description.Trim();
                        }

                        group.Save();
                    }
                    else
                    {

                        CredentialRoleModel adminrole = model.Roles.FirstOrDefault(p => p.RoleSelected && p.RoleName == SystemRoleType.TridentAdministrators.ToString());
                        if (adminrole == null)
                        {
                            // If the current Group Model is not having any admin roles, Check whether the registry is having any active  user having administrator group / role  
                            if (Group.CommonSearches.GetAllAdminGroupsCount(this.registryConnection, model.Id) == 0)
                            {
                                throw new TridentCustomException(ManagementStudioResourceManager.GetString("ErrorIFNOAdminIsActive"));
                            }
                        }
                        else if (Group.CommonSearches.GetAllAdminGroupsCount(this.registryConnection, model.Id) == 0 && !model.Status)
                        {
                            throw new TridentCustomException(ManagementStudioResourceManager.GetString("ErrorIFNOAdminIsActive"));
                        }

                        group = Group.Load(model.Id, this.registryConnection);
                        group.Name = model.Name.Trim();
                        group.Enabled = model.Status;
                        if (!string.IsNullOrEmpty(model.Description))
                        {
                            group.Description = model.Description.Trim();
                        }

                        group.Save();
                    }

                    this.SaveGroupCredentials(group, model);
                    this.SaveGroupUsers(group, model);
                    this.SaveGroupRoles(group, model);

                    group.Refresh();
                    this.GrantRegistryAccess(group);
                    return true;
                }
                else
                {
                    group = null;
                    return false;
                }
            }
            catch (TridentCustomException)
            {
                throw;
            }
            catch (RecordNotFoundException)
            {
                throw new TridentCustomException(ManagementStudio.GroupsRetrieveError);
            }

            catch (Exception ex)
            {
                TridentErrorHandler.ProcessKnownExceptionsInBusinessLogic(ex);
                throw new TridentCustomException("Error while saving the group");
            }

        }

        /// <summary>
        /// Fetches the category activitys.
        /// </summary>
        /// <param name="categoryViewModel">The category view model.</param>
        /// <returns>The list of sctivitys in model format.</returns>
        public Collection<WorkflowViewModel> FetchCategoryActivitys(CategoryViewModel categoryViewModel)
        {
            Collection<WorkflowViewModel> wFlows = new Collection<WorkflowViewModel>();
            try
            {
                Namespace nsCategory = Namespace.Load(categoryViewModel.Id, this.registryConnection);
                nsCategory.Activitys.Where(item => !item.IsDeleted && (item.IsLatestVersion())).ForEach(act => wFlows.Add(new WorkflowViewModel(act)));
            }
            catch (RecordNotFoundException ex)
            {
                TridentErrorHandler.HandleUIException(ex);
            }
            catch (InvalidOperationException ex)
            {
                TridentErrorHandler.HandleUIException(ex);
            }
            catch (Exception ex)
            {
                TridentErrorHandler.HandleUIException(ex);
            }

            return wFlows;
        }

        /// <summary>
        /// Fetches all User.
        /// </summary>
        /// <returns>The list of User </returns>
        public Collection<User> GetAllUsers()
        {
            Collection<User> users = new Collection<User>();
            try
            {
                users = User.CommonSearches.GetAllUsers(this.registryConnection);
            }
            catch (Exception ex)
            {
                TridentErrorHandler.ProcessKnownExceptionsInBusinessLogic(ex);
                TridentErrorHandler.HandleAndThrowBusinessLogicException(ex, TridentErrorConstants.ErrorNumber1000000064,
                    ManagementStudioResourceManager.GetString("UsersRetrieveError"));
            }
            return users;
        }

        /// <summary>
        /// Get all active Users
        /// </summary>
        /// <param name="userName">Username</param>
        /// <returns>The list of User </returns>
        public ObservableCollection<SearchUserModel> GetAllActiveUsers()
        {
            Collection<User> users = new Collection<User>();
            ObservableCollection<SearchUserModel> usersModel = new ObservableCollection<SearchUserModel>();
            try
            {
                users = User.CommonSearches.GetAllActiveUsers(this.registryConnection);
                users.ForEach(user => usersModel.Add(new SearchUserModel(user.Name)));
            }
            catch (Exception ex)
            {
                TridentErrorHandler.ProcessKnownExceptionsInBusinessLogic(ex);
                TridentErrorHandler.HandleAndThrowBusinessLogicException(ex, TridentErrorConstants.ErrorNumber1000000064,
                    ManagementStudioResourceManager.GetString("UsersRetrieveError"));
            }

            return usersModel;
        }

        /// <summary>
        /// Fetches all active groups other than passed in group Name
        /// </summary>
        /// <param name="groupName">Username</param>
        /// <returns>The list of Groups </returns>
        public Collection<Group> GetAllGroupByFilter(string userName)
        {
            Collection<Group> groups = new Collection<Group>();

            try
            {
                groups = Group.CommonSearches.GetAllGroupsByFilter(userName, this.registryConnection);
            }
            catch (Exception ex)
            {
                TridentErrorHandler.ProcessKnownExceptionsInBusinessLogic(ex);
                TridentErrorHandler.HandleAndThrowBusinessLogicException(ex, TridentErrorConstants.ErrorNumber1000000064,
                    ManagementStudioResourceManager.GetString("GroupsRetrieveError"));
            }
            return groups;
        }

        /// <summary>
        /// Fetches all active users other than passed in user Name
        /// </summary>
        /// <param name="userId">UserId</param>
        /// <returns>The list of User </returns>
        public Collection<User> GetAllUserByFilter(Guid userId)
        {
            Collection<User> users = new Collection<User>();

            try
            {
                users = User.CommonSearches.GetAllUserByFilter(userId, this.registryConnection);
            }
            catch (Exception ex)
            {
                TridentErrorHandler.ProcessKnownExceptionsInBusinessLogic(ex);
                TridentErrorHandler.HandleAndThrowBusinessLogicException(ex, TridentErrorConstants.ErrorNumber1000000064,
                    ManagementStudioResourceManager.GetString("UsersRetrieveError"));
            }
            return users;
        }

        /// <summary>
        /// Fetches all Groups.
        /// </summary>
        /// <returns>The list of Groups </returns>
        public Collection<Group> GetAllGroups()
        {
            Collection<Group> groups = new Collection<Group>();
            try
            {
                groups = new Collection<Group>(Group.CommonSearches.GetAllGroups(this.registryConnection));
            }
            catch (Exception ex)
            {
                TridentErrorHandler.ProcessKnownExceptionsInBusinessLogic(ex);
                TridentErrorHandler.HandleAndThrowBusinessLogicException(ex, TridentErrorConstants.ErrorNumber1000000065,
                    ManagementStudioResourceManager.GetString("GroupsRetrieveError"));
            }

            return groups;
        }

        /// <summary>
        /// Fetches all Groups.
        /// </summary>
        /// <returns>The list of Groups </returns>
        public Collection<Group> GetAllActiveGroups()
        {
            Collection<Group> groups = new Collection<Group>();

            try
            {
                groups = new Collection<Group>(Group.CommonSearches.GetAllActiveGroups(this.registryConnection));
            }
            catch (Exception ex)
            {
                TridentErrorHandler.ProcessKnownExceptionsInBusinessLogic(ex);
                TridentErrorHandler.HandleAndThrowBusinessLogicException(ex, TridentErrorConstants.ErrorNumber1000000065,
                    ManagementStudioResourceManager.GetString("GroupsRetrieveError"));
            }

            return groups;
        }

        /// <summary>
        /// Retrieve all nodes from the registry.
        /// </summary>
        /// <returns>The list of all nodes in the registry.</returns>
        public Collection<Machine> GetNodes()
        {
            Collection<Machine> machines = null;
            try
            {
                machines = Machine.CommonSearches.GetAllNodes(this.registryConnection);
            }
            catch (RecordNotFoundException)
            {
                // Assign machines to null.
                machines = null;
            }
            catch (Exception ex)
            {
                TridentErrorHandler.ProcessKnownExceptionsInBusinessLogic(ex);
                TridentErrorHandler.HandleAndThrowBusinessLogicException(ex,
                    TridentErrorConstants.ErrorNumber1000000032,
                    ManagementStudioResourceManager.GetString("NodesRetrieveError"));
            }

            return machines;
        }

        /// <summary>
        /// Save the node details.
        /// </summary>
        /// <param name="nodeModel"></param>
        /// <returns>The modified node details.</returns>
        public Machine SaveNode(NodeViewModel nodeModel)
        {
            if (nodeModel == null)
            {
                throw new ArgumentNullException("nodeModel");
            }

            try
            {
                return this.EditNode(nodeModel);
            }
            catch (RecordNotFoundException ex)
            {
                TridentErrorHandler.HandleAndThrowBusinessLogicException(ex,
                  TridentErrorConstants.ErrorNumber1000000033,
                  ManagementStudioResourceManager.GetString("NodeSaveError"));
            }
            catch (Exception ex)
            {
                TridentErrorHandler.ProcessKnownExceptionsInBusinessLogic(ex);
                TridentErrorHandler.HandleAndThrowBusinessLogicException(ex,
                 TridentErrorConstants.ErrorNumber1000000033,
                 ManagementStudioResourceManager.GetString("NodeSaveError"));
            }
            return null;
        }

        /// <summary>
        /// Deletes the user.
        /// </summary>
        /// <param name="ownerId">The new owner id.</param>
        /// <param name="userId">The user id.</param>
        public void DeleteUser(Guid ownerId, Guid userId)
        {
            # region Validation of Arguments

            if (ownerId == null)
            {
                throw new ArgumentNullException("ownerId");
            }

            if (userId == null)
            {
                throw new ArgumentNullException("userId");
            }

            #endregion

            try
            {
                // Load the new owner of the deleted user's objects.
                User newOwner = User.Load(ownerId, this.registryConnection);

                // Load the deleted user.
                User deleteUser = User.Load(userId, this.registryConnection);

                // Transfer all workflows of the deleted user to the new owner's private workflow category.
                Namespace newOwnerMyWorkflows = newOwner.Namespaces.Where(name => name.Name.Equals(TridentResourceManager.GetString("WorkFlowTreeHeader"))).FirstOrDefault();
                Namespace delUserMyWorkflows = deleteUser.Namespaces.Where(name => name.Name.Equals(TridentResourceManager.GetString("WorkFlowTreeHeader"))).FirstOrDefault();

                // Recurse through all the activities. In the case of duplicates append user name and date time stamp.
                if (newOwnerMyWorkflows != null && delUserMyWorkflows != null)
                {
                    Collection<Activity> workflows = new Collection<Activity>();
                    this.CollateWorkflows(delUserMyWorkflows, workflows);

                    Collection<Activity> mergedWfs = new Collection<Activity>(workflows.ToList());
                    newOwnerMyWorkflows.Activitys.Where(activity => (!activity.IsDeleted && activity.IsLatestVersion()))
                        .ForEach(activity => mergedWfs.Add(activity));

                    var wfNameGroup = from wf in mergedWfs
                                      group wf by wf.Name into nameGroup
                                      select new
                                      {
                                          wfName = nameGroup.Key,
                                          wfGroup = nameGroup
                                      };

                    var invalidGrp = wfNameGroup.FirstOrDefault(grp => grp.wfGroup.Count() > 1);

                    if (invalidGrp != null)
                    {
                        throw new TridentCustomException(ManagementStudioResourceManager.GetString("userDeleteFail"));
                    }
                    else
                    {
                        // Transfer ownership to the new owner.
                        IEnumerable<Activity> ownerActivity = Activity.CommonSearches.GetAllActivitiesOfOwner(this.registryConnection, userId);
                        if (ownerActivity != null)
                        {
                            ownerActivity.ForEach(p => { p.Owner = newOwner; p.Save(); });
                        }

                        workflows.ForEach(wf => newOwnerMyWorkflows.Activitys.Add(wf));
                    }
                }

                this.WorkflowDeleteRecursive(delUserMyWorkflows);

                // Delete ACL Info for the User
                Collection<ActivityACL> userACLs = deleteUser.GetActivityACLs();
                if (userACLs != null)
                {
                    foreach (ActivityACL userACL in userACLs)
                    {
                        userACL.Delete();
                    }
                }

                //Mark the user as deleted.
                deleteUser.IsDeleted = true;
                deleteUser.Save();

            }
            catch (RecordNotFoundException)
            {
                throw new TridentCustomException(ManagementStudioResourceManager.GetString("UserAlreadyDeleted"));
            }
            catch (TridentCustomException ex)
            {
                throw new TridentCustomException(ex.Message, ex);
            }
            catch (Exception ex)
            {
                TridentErrorHandler.ProcessKnownExceptionsInBusinessLogic(ex);
                TridentErrorHandler.HandleAndThrowBusinessLogicException(ex,
                  TridentErrorConstants.ErrorNumber1000000062,
                  ManagementStudioResourceManager.GetString("UserDeleteError"));
            }
        }

        /// <summary>
        /// Gets the system policy.
        /// </summary>
        /// <returns></returns>
        public SystemPolicy GetSystemPolicy()
        {
            SystemPolicy sysPol = null;
            try
            {
                sysPol = SystemPolicy.Get(registryConnection);
                sysPol.Refresh();
            }
            catch (TridentCustomException)
            {
                throw;
            }
            catch (Exception ex)
            {
                TridentErrorHandler.ProcessKnownExceptionsInBusinessLogic(ex);
            }
            return sysPol;
        }

        /// <summary>
        /// Soft delete the group after assiging the users to Selected user
        /// </summary>
        /// <param name="groupId"></param>
        public void DeleteGroup(Guid groupId)
        {
            try
            {
                Group deleteGroup = Group.Load(groupId, this.registryConnection);
                if (deleteGroup != null)
                {
                    SystemRole adminRole = deleteGroup.SystemRoles.FirstOrDefault(role => role.BuiltinRole.Equals(SystemBuiltinRoleType.Administrators));
                    User loggedInUser = deleteGroup.Users.FirstOrDefault(user => ((IObject)user).ID.Equals(((IObject)TridentAuthentication.LoggedInUser).ID));
                    if (adminRole != null && loggedInUser != null)
                    {
                        throw new TridentCustomException(ManagementStudioResourceManager.GetString(("ErrorGroupContainLogeedInUserOnDelete")));
                    }

                    deleteGroup.IsDeleted = true;
                    deleteGroup.Save();
                }
            }
            catch (RecordNotFoundException)
            {
                throw new TridentCustomException(ManagementStudioResourceManager.GetString("GroupAlreadyDeleted"));
            }

            catch (TridentCustomException)
            {
                throw;
            }
            catch (Exception ex)
            {
                TridentErrorHandler.ProcessKnownExceptionsInBusinessLogic(ex);
                TridentErrorHandler.HandleAndThrowBusinessLogicException(ex,
                  TridentErrorConstants.ErrorNumber1000000063,
                  ManagementStudioResourceManager.GetString("GroupDeleteError"));
            }
        }

        /// <summary>
        /// Delete the node. It is a soft delete.
        /// </summary>
        /// <param name="guid">Guid of the node to be deleted.</param>
        public void DeleteNode(Guid nodeId)
        {
            if (nodeId == Guid.Empty)
            {
                throw new ArgumentNullException("nodeId");
            }

            try
            {
                this.SoftDeleteNode(nodeId);
            }
            catch (RecordNotFoundException ex)
            {
                TridentErrorHandler.HandleAndThrowBusinessLogicException(ex,
                  TridentErrorConstants.ErrorNumber1000000034,
                  ManagementStudioResourceManager.GetString("NodeDeleteError"));
            }
            catch (Exception ex)
            {
                TridentErrorHandler.ProcessKnownExceptionsInBusinessLogic(ex);
                TridentErrorHandler.HandleAndThrowBusinessLogicException(ex,
                  TridentErrorConstants.ErrorNumber1000000034,
                  ManagementStudioResourceManager.GetString("NodeDeleteError"));
            }
        }

        /// <summary>
        /// Retrieve the specified node.
        /// </summary>
        /// <param name="guid">The guid of the node to retrieve.</param>
        /// <returns>The required node.</returns>
        public Machine GetNode(Guid nodeId)
        {
            if (nodeId == Guid.Empty)
            {
                throw new ArgumentNullException("nodeId");
            }
            try
            {
                return Machine.Load(nodeId, this.registryConnection);
            }
            catch (RecordNotFoundException ex)
            {
                TridentErrorHandler.HandleAndThrowBusinessLogicException(ex,
                  TridentErrorConstants.ErrorNumber1000000035,
                  ManagementStudioResourceManager.GetString("NodeRetrieveError"));
            }
            catch (Exception ex)
            {
                TridentErrorHandler.ProcessKnownExceptionsInBusinessLogic(ex);
                TridentErrorHandler.HandleAndThrowBusinessLogicException(ex,
                   TridentErrorConstants.ErrorNumber1000000035,
                   ManagementStudioResourceManager.GetString("NodeRetrieveError"));
            }
            return null;
        }

        /// <summary>
        /// Saves the workflow.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns></returns>
        public Activity SaveWorkflow(WorkflowCatalogViewModel model)
        {
            if (model == null)
            {
                throw new ArgumentNullException("model");
            }

            Activity activity = null;
            try
            {
                bool newVersionCreated = false;
                Activity currentActivity = Activity.Load(model.Id, this.registryConnection);

                if (!currentActivity.Security.Rights.AuthorWorkflow.Check(TridentAuthentication.LoggedInUser))
                {
                    TridentErrorHandler.ThrowTridentCustomException(TridentErrorConstants.ErrorNumber4000085,
                        TridentCommonResourceManager.GetString("WorkflowPermissionDenied"));
                }

                if (currentActivity == null || currentActivity.IsDeleted == true)
                {
                    throw new TridentCustomException(ManagementStudioResourceManager.GetString("SaveWorkflowError"));
                }

                if (!CategoriesComposer.ValidateWorkflowName(model.Parent.Id, model.Id, model.Name, this.registryConnection))
                {
                    throw new TridentCustomException(ManagementStudioResourceManager.GetString("WorkflowNameExistsError"));
                }

                bool isLatestVersion = currentActivity.IsLatestVersion();

                // If labelled workflow then do not create a new version on save.
                if (!string.IsNullOrEmpty(currentActivity.VersionLabel) && !isLatestVersion)
                {
                    activity = currentActivity;
                    activity.VersionLabel = model.VersionLabel.Trim();
                }
                else
                {
                    if (!isLatestVersion)
                    {
                        TridentErrorHandler.ThrowTridentCustomException(TridentErrorConstants.ErrorNumber1000000062,
                            ManagementStudioResourceManager.GetString("WorkflowNewerVersionExists"));
                    }
                    activity = currentActivity.CreateNewVersion(this.registryConnection);
                    activity.VersionLabel = string.Empty;

                    // Create version assignments when the save occurs. This saves a couple of DB calls.
                    newVersionCreated = true;
                }
                activity.Name = model.Name.Trim();
                string label = activity.Name;
                if (!string.IsNullOrEmpty(model.Label) && !string.IsNullOrEmpty(model.Label.Trim()))
                {
                    label = model.Label.Trim();
                }

                activity.Label = label;

                if (!string.IsNullOrEmpty(model.Contact) && !string.IsNullOrEmpty(model.Contact.Trim()))
                {
                    activity.Contacts = model.Contact.Trim();
                }

                if (!string.IsNullOrEmpty(model.Comments) && !string.IsNullOrEmpty(model.Comments.Trim()))
                {
                    activity.Comments = model.Comments.Trim();
                }

                if (!string.IsNullOrEmpty(model.Author) && !string.IsNullOrEmpty(model.Author.Trim()))
                {
                    activity.Author = model.Author.Trim();
                }


                activity.Description = string.IsNullOrEmpty(model.Description) ? string.Empty : model.Description.Trim();

                if (!string.IsNullOrEmpty(model.Keywords) && !string.IsNullOrEmpty(model.Keywords.Trim()))
                {
                    activity.Keywords = model.Keywords.Trim();
                }

                activity.IsInteractive = model.IsInteractive;
                activity.Save();

                // Create the version relationships and the sequences if a new version was created.
                if (newVersionCreated)
                {
                    //Inherit the ACL Info
                    Activity.InheritACLInfo(currentActivity, activity, this.registryConnection);

                    ActivityVersion versionRelationship =
                        ActivityVersion.Create(currentActivity, activity, VersionRelationshipType.Concrete, this.registryConnection);
                    currentActivity.NewerVersions.Add(versionRelationship);

                    this.CreateActivitySequences(currentActivity, activity);

                    try
                    {
                        this.registryConnection.AutoSave = true;
                        activity.Icon = currentActivity.Icon;
                    }
                    finally
                    {
                        this.registryConnection.AutoSave = false;
                    }
                }

                if (model.Parent != null)
                {
                    Namespace parent = Namespace.Load(model.Parent.Id, this.registryConnection);
                    if (parent != null)
                    {
                        activity.Namespaces.Clear();
                        activity.Namespaces.Add(parent);
                    }
                }

                if (!string.IsNullOrEmpty(model.IconPath) && File.Exists(model.IconPath))
                {
                    Image img = null;
                    try
                    {
                        img = Image.FromFile(model.IconPath);
                    }
                    catch
                    {
                        // Some icon file formats throw an exception. Need to use the icon class instead. 
                        Icon icon = new Icon(model.IconPath);
                        img = icon.ToBitmap();
                    }
                    if (img != null)
                    {
                        try
                        {
                            this.registryConnection.AutoSave = true;
                            img.Tag = System.IO.Path.GetFileName(model.IconPath);
                            activity.Icon = img;
                        }
                        finally
                        {
                            this.registryConnection.AutoSave = false;
                        }
                    }
                }
                else if (null == model.Icon)
                {
                    try
                    {
                        this.registryConnection.AutoSave = true;
                        activity.Icon = null;
                    }
                    finally
                    {
                        this.registryConnection.AutoSave = false;
                    }
                }
            }
            catch (TridentCustomException)
            {
                throw;
            }
            catch (Exception ex)
            {
                TridentErrorHandler.ProcessKnownExceptionsInBusinessLogic(ex);
                TridentErrorHandler.HandleAndThrowBusinessLogicException(ex, TridentErrorConstants.ErrorNumber1000000044, "Unable to save workflow");
            }

            return activity;
        }

        /// <summary>
        /// Open the trident composer window.
        /// </summary>
        /// <param name="selectedWorkflow">The default worklfow to open.</param>
        [EnvironmentPermissionAttribute(SecurityAction.LinkDemand, Unrestricted = true)]
        public void OpenComposerForNewWorkflow()
        {
            try
            {
                // get app name from config file.
                string appName = ConfigurationManager.AppSettings["ComposerApplication"];

                // Get the installation directory.
                string installDir = WorkflowManagerService.GetInstallationLocation();

                // Get the directory which contains the trident composer application.
                string appLocation = Path.Combine(installDir, appName);

                // Throw exception if the app doesnt exist.
                if (!File.Exists(appLocation))
                {
                    TridentErrorHandler.ThrowTridentCustomException(TridentErrorConstants.ErrorNumber1000000019,
                        ManagementStudioResourceManager.GetString("ComposerApplicationAbsent"));
                }

                string args = "-n";

                // Open the composer.
                WorkflowManagerService.OpenApplication(appLocation, installDir, args);
            }
            catch (IOException ex)
            {
                TridentErrorHandler.HandleAndThrowBusinessLogicException(ex,
                  TridentErrorConstants.ErrorNumber100000007,
                  ManagementStudioResourceManager.GetString("AvailableWorkflowComposerOpenError"));
            }
            catch (InvalidOperationException ex)
            {
                TridentErrorHandler.HandleAndThrowBusinessLogicException(ex,
                  TridentErrorConstants.ErrorNumber100000007,
                  ManagementStudioResourceManager.GetString("AvailableWorkflowComposerOpenError"));
            }
            catch (System.ComponentModel.Win32Exception ex)
            {
                TridentErrorHandler.HandleAndThrowBusinessLogicException(ex,
                  TridentErrorConstants.ErrorNumber100000007,
                  ManagementStudioResourceManager.GetString("AvailableWorkflowComposerOpenError"));
            }
        }

        /// <summary>
        /// Deletes the workflow.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns></returns>
        public bool DeleteWorkflow(WorkflowCatalogViewModel model)
        {
            try
            {
                Activity activity = Activity.Load(model.Id, this.registryConnection);
                if (activity != null)
                {
                    WorkflowComposer.DeleteWorkflow(activity);
                    return true;
                }
                else
                {
                    throw new TridentCustomException(string.Format(CultureInfo.CurrentCulture, ManagementStudioResourceManager.GetString("WorkflowNotInRegistry"), model.Name));
                }
            }
            catch (TridentCustomException)
            {
                throw;
            }
            catch (Exception ex)
            {
                TridentErrorHandler.ProcessKnownExceptionsInBusinessLogic(ex);
                TridentErrorHandler.HandleAndThrowBusinessLogicException(ex, TridentErrorConstants.ErrorNumber1000000043, ManagementStudioResourceManager.GetString("WorkflowDeleteError"));
            }

            return false;
        }

        /// <summary>
        /// Saves the activity.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns>
        /// True for success, else false.
        /// </returns>
        public Activity SaveActivity(ActivityViewModel model)
        {
            Activity savedActivity = null;
            Activity activity = this.FetchActivityFromModel(model);
            if (null != activity)
            {
                savedActivity = this.UpdateActivity(model, activity);
            }

            return savedActivity;
        }

        /// <summary>
        /// Imports the activity.
        /// </summary>
        /// <param name="dllPath">The DLL path.</param>
        /// <returns>Status of the operation</returns>
        public bool ImportActivity(Collection<FileReference> references)
        {
            bool importStatus = true;
            if (this.registryConnection != null)
            {
                ImportActivityProxy importProxy = new ImportActivityProxy(this.registryConnection, references, false);
                importStatus = (bool)importProxy.Execute();
            }

            return importStatus;
        }

        /// <summary>
        /// Fetches the related workflows.
        /// </summary>
        /// <param name="activityModel">The activity model.</param>
        /// <returns>The collection of related workflows.</returns>
        public Collection<WorkflowViewModel> FetchRelatedWorkflows(ActivityViewModel activityModel)
        {
            Activity activity = this.FetchActivityFromModel(activityModel);
            return this.FetchRelatedWorkflowsByActivity(activity, false);
        }

        /// <summary>
        /// Gets the type initializers.
        /// </summary>
        /// <returns>
        /// The collection of type initializers.
        /// </returns>
        public IEnumerable<TypeInitializer> GetTypeInitializers()
        {
            try
            {
                return TypeInitializer.CommonSearches.GetAvailableTypeInitializers(this.registryConnection);
            }
            catch (RecordNotFoundException ex)
            {
                TridentErrorHandler.HandleUIException(ex);
            }
            catch (Exception ex)
            {
                TridentErrorHandler.ProcessKnownExceptionsInBusinessLogic(ex);
                TridentErrorHandler.HandleAndThrowBusinessLogicException(ex,
                    TridentErrorConstants.ErrorNumber1000000047,
                    ManagementStudioResourceManager.GetString("TypeInitializersRetrieveError"));
            }

            return null;
        }

        /// <summary>
        /// Saves the type initializer.
        /// </summary>
        /// <param name="typeInitializerModel">The type initializer model.</param>
        /// <returns>The registry version of the type initializer if save succeeds, else null.</returns>
        public TypeInitializer SaveTypeInitializer(TypeInitializerModel typeInitializerModel)
        {
            if (null == typeInitializerModel)
            {
                throw new ArgumentNullException("typeInitializerModel");
            }

            try
            {
                return this.EditTypeInitializer(typeInitializerModel);
            }
            catch (RecordNotFoundException ex)
            {
                TridentErrorHandler.HandleAndThrowBusinessLogicException(ex,
                     TridentErrorConstants.ErrorNumber1000000048,
                     ManagementStudioResourceManager.GetString("TypeInitializerSaveError"));
            }
            catch (Exception ex)
            {
                TridentErrorHandler.ProcessKnownExceptionsInBusinessLogic(ex);
                TridentErrorHandler.HandleAndThrowBusinessLogicException(ex,
                    TridentErrorConstants.ErrorNumber1000000049,
                    ManagementStudioResourceManager.GetString("TypeInitializerSaveError"));
            }

            return null;
        }

        /// <summary>
        /// Imports the type initializer.
        /// </summary>
        /// <param name="dllPath">The DLL path.</param>
        /// <returns>Value indicating the success or failure of import.</returns>
        public OperationStatus ImportTypeInitializer(string dllPath)
        {
            OperationStatus importSuccess = OperationStatus.Success;
            if (this.registryConnection != null)
            {
                ImportTypeInitializerProxy importTypeInitializer = new ImportTypeInitializerProxy(dllPath, this.registryConnection);
                return importTypeInitializer.Execute();
            }

            return importSuccess;
        }

        /// <summary>
        /// Deletes the type initializer.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns>Value indicating the success or failure of delete.</returns>
        public bool DeleteTypeInitializer(TypeInitializerModel model)
        {
            if (null == model)
            {
                throw new ArgumentNullException("model");
            }

            return this.TypeInitializerDelete(model);
        }

        /// <summary>
        /// Fetches the related workflows.
        /// </summary>
        /// <param name="activityModel">The activity model.</param>
        /// <returns>The collection of related workflows.</returns>
        public Collection<WorkflowViewModel> FetchRelatedWorkflows(TypeInitializerModel typeInitializerModel)
        {
            if (null == typeInitializerModel)
            {
                throw new ArgumentNullException("typeInitializerModel");
            }

            return new Collection<WorkflowViewModel>(this.FetchTypeInitializerRelatedWorkflows(typeInitializerModel));
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="deletePackage"></param>
        public void DeletePackage(Guid delPackage)
        {
            if (delPackage.Equals(Guid.Empty))
            {
                throw new ArgumentNullException("delPackage");
            }

            try
            {
                bool cancelDelete = false;
                AssemblyPackage packageToDelete = AssemblyPackage.Load(delPackage, this.registryConnection);

                // If an activity is referenced in a workflow then do not delete the package.
                foreach (Activity activity in packageToDelete.Activitys)
                {
                    if (IsActivityReferencedInWorkflow(activity))
                    {
                        cancelDelete = true;
                        break;
                    }
                }
                if (cancelDelete)
                {
                    TridentErrorHandler.ThrowTridentCustomException(TridentErrorConstants.ErrorNumber1000000057,
                        ManagementStudioResourceManager.GetString("ActivityUsedInAWorkflowError"));
                }

                // Delete all activities in the package.
                foreach (Activity activity in packageToDelete.Activitys)
                {
                    activity.DeleteUnused();
                }

                // Clear the package contents.
                foreach (AssemblyImage assemblyImage in packageToDelete.AssemblyImages)
                {
                    bool deleteAssemblyContinue = true;

                    // If the image is shared across packages then dont delete.
                    foreach (AssemblyPackage assemblyPackage in assemblyImage.AssemblyPackages)
                    {
                        if (!assemblyPackage.Equals(packageToDelete) && !assemblyPackage.IsDeleted)
                        {
                            deleteAssemblyContinue = false;
                            break;
                        }
                    }
                    if (deleteAssemblyContinue)
                    {
                        assemblyImage.DeleteUnused();
                    }
                }

                // Delete the Package.
                packageToDelete.IsDeleted = true;
                packageToDelete.Save();
            }
            catch (TridentCustomException)
            {
                throw;
            }
            catch (RecordNotFoundException)
            {
                TridentErrorHandler.ThrowTridentCustomException(TridentErrorConstants.ErrorNumber1000000058,
                        ManagementStudioResourceManager.GetString("ErrorAssemblyNotFound"));
            }
            catch (Exception ex)
            {
                TridentErrorHandler.ProcessKnownExceptionsInBusinessLogic(ex);
                TridentErrorHandler.ThrowTridentCustomException(TridentErrorConstants.ErrorNumber1000000059,
                        ManagementStudioResourceManager.GetString("AssemblyDeleteError"));
            }
        }

        /// <summary>
        /// Retrieve all the assembly packages in the registry.
        /// </summary>
        /// <returns>Collection of all the assembly packages in the registry.</returns>
        public Collection<AssemblyPackageViewModel> GetAllAssemblyPackages()
        {
            Collection<AssemblyPackageViewModel> packageModels = new Collection<AssemblyPackageViewModel>();
            try
            {
                Collection<AssemblyPackage> assemblyPackages = AssemblyPackage.CommonSearches.GetAssemblyPackages(this.registryConnection);
                foreach (AssemblyPackage package in assemblyPackages)
                {
                    package.DataReferenceProviders.GetEnumerator();
                    bool isDataProviderPackage = package.DataReferenceProviders.Count > 0;

                    package.TypeInitializers.GetEnumerator();
                    bool isTypeInitializerPackage = package.TypeInitializers.Count > 0;

                    if (!isDataProviderPackage && !isTypeInitializerPackage)
                    {
                        // Create a model for each of the packages.
                        AssemblyPackageViewModel packageModel = new AssemblyPackageViewModel(package);

                        // Add its related activities to the model.
                        foreach (Activity activity in package.Activitys)
                        {
                            bool isLinked = IsActivityReferencedInWorkflow(activity);
                            packageModel.PackageReferences.Add(
                                new AssemblyPackageAssociationViewModel()
                                {
                                    Name = string.IsNullOrEmpty(activity.Label) ? activity.Name : activity.Label,
                                    IsLinked = isLinked ? ManagementStudio.AssembleyCatalogActive : ManagementStudio.AssembleyCatalogInActive
                                });
                            packageModel.AssignActivityIcon();
                        }

                        if (package.Activitys.Count > 0)
                        {
                            packageModel.ListLabel = ManagementStudioResourceManager.GetString("AssemblyPackageActivtyLabel");
                        }

                        packageModels.Add(packageModel);
                    }
                }
            }
            catch (RecordNotFoundException ex)
            {
                TridentErrorHandler.HandleAndThrowBusinessLogicException(ex, TridentErrorConstants.ErrorNumber1000000060, ManagementStudioResourceManager.GetString("ErrorAssemblyNotFound"));
            }
            catch (Exception ex)
            {
                TridentErrorHandler.ProcessKnownExceptionsInBusinessLogic(ex);
                TridentErrorHandler.HandleAndThrowBusinessLogicException(ex, TridentErrorConstants.ErrorNumber1000000061, ManagementStudioResourceManager.GetString("ErrorAssemblyPackageLoad"));
            }

            return packageModels;
        }

        /// <summary>
        /// Fetches all enabled security principals.
        /// </summary>
        /// <returns></returns>
        public IEnumerable<ISecurityPrincipal> FetchAllEnabledSecurityPrincipals(bool includeEveryone)
        {
            List<ISecurityPrincipal> enabledSecPrin = new List<ISecurityPrincipal>();
            try
            {
                enabledSecPrin.AddRange(User.CommonSearches.GetAllEnabledUsers(this.registryConnection).Cast<ISecurityPrincipal>());
                enabledSecPrin.AddRange(Group.CommonSearches.GetAllEnabledGroups(this.registryConnection).Cast<ISecurityPrincipal>());
                if (includeEveryone)
                {
                    enabledSecPrin.Add(SystemPolicy.Get(this.registryConnection).Everyone);
                    User anonymous = User.Load("Anonymous", this.registryConnection);
                    enabledSecPrin.Add(anonymous);
                }
            }
            catch (Exception ex)
            {
                TridentErrorHandler.ProcessKnownExceptionsInBusinessLogic(ex);
                TridentErrorHandler.HandleAndThrowBusinessLogicException(ex, TridentErrorConstants.ErrorNumber1000000068, ManagementStudioResourceManager.GetString("FetchSecurityPrincipalsError"));
            }
            return enabledSecPrin;
        }

        /// <summary>
        /// Gets the users my workflows.
        /// </summary>
        /// <param name="categories">The categories.</param>
        public void GetMyWorkflowsForCurrentUser(Collection<Namespace> categories)
        {
            this.GetMyWorkflowsForUser(categories, this.currentUser);
        }

        /// <summary>
        /// Gets all users my workflows.
        /// </summary>
        /// <param name="categories">The categories.</param>
        public void GetAllUsersMyWorkflows(Collection<Namespace> categories)
        {
            List<User> allUsers = User.LoadAll(this.registryConnection);
            foreach (User user in allUsers)
            {
                if ((user as IObject).ID != (this.currentUser as IObject).ID)
                {
                    this.GetMyWorkflowsForUser(categories, user);
                }
            }
        }

        /// <summary>
        /// Gets all shared workflows.
        /// </summary>
        /// <returns></returns>
        public Collection<Activity> GetAllSharedWorkflowsForCurrentUser()
        {
            Collection<Activity> allPermittedActivities = new Collection<Activity>();
            try
            {
                allPermittedActivities = new Collection<Activity>(Activity.LoadAll(this.registryConnection).Where(
                    activity => this.CheckActivityValidityForNormalUser(activity)).ToList());
            }
            catch (RecordNotFoundException) { }

            return allPermittedActivities;
        }

        /// <summary>
        /// Fetches the current user.
        /// </summary>
        /// <returns></returns>
        public User FetchCurrentUser()
        {
            return this.currentUser;
        }

        /// <summary>
        /// Verify the type intialiser has been refered in any workflows
        /// </summary>
        /// <param name="typeIntialiserId">typeIntialiserId</param>
        /// <returns>true if its not has been refered, False otherwise</returns>
        private bool IsTypeIntialiserReferedInWorkflow(Guid typeIntialiserId)
        {
            List<WorkflowViewModel> relatedWorkflows = new List<WorkflowViewModel>();
            TypeInitializer typeInitializer = TypeInitializer.Load(typeIntialiserId, this.registryConnection);
            if (typeInitializer != null && !typeInitializer.IsDeleted)
            {
                string supportingType = typeInitializer.RelatedType.TypeName;
                ActivityParameter.LoadAll(this.registryConnection)
                    .Where(activityParam => activityParam.Type.Equals(supportingType, StringComparison.OrdinalIgnoreCase))
                    .ForEach(activityParam => relatedWorkflows.AddRange(this.FetchRelatedWorkflowsByActivity(activityParam.Activity, false)));

                relatedWorkflows = relatedWorkflows.Distinct(new WorkflowModelComparer()).ToList();
            }

            return (relatedWorkflows.Count != 0);
        }

        #endregion

        #region Private methods

        /// <summary>
        /// Collates the workflows.
        /// </summary>
        /// <param name="category">The category.</param>
        /// <param name="workflows">The workflows.</param>
        private void CollateWorkflows(Namespace category, Collection<Activity> workflows)
        {
            category.Activitys.Where(activity => !activity.IsDeleted && activity.IsLatestVersion())
                .ForEach(activity => workflows.Add(activity));
            category.Children.ForEach(childCategory => this.CollateWorkflows(childCategory, workflows));
        }

        /// <summary>
        /// Deletes the workflows in the category and its child categories.
        /// </summary>
        /// <param name="category">The category.</param>
        private void WorkflowDeleteRecursive(Namespace category)
        {
            category.Activitys.Clear();
            category.Children.ForEach(childCategory => this.WorkflowDeleteRecursive(childCategory));
        }

        /// <summary>
        /// Gets the users my workflows.
        /// </summary>
        /// <param name="categories">The categories.</param>
        private void GetMyWorkflowsForUser(Collection<Namespace> categories, User user)
        {
            try
            {
                if (user != null)
                {
                    Namespace userRoot = user.WorkflowRoot;
                    if (userRoot != null)
                    {
                        userRoot.Refresh();
                        Namespace currentUserRoot = userRoot.Children.Where(
                            child => child.User != null).FirstOrDefault(
                            child => child.User.Equals(user));

                        if (currentUserRoot != null)
                        {
                            categories.Add(currentUserRoot);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                TridentErrorHandler.ProcessKnownExceptionsInBusinessLogic(ex);
                TridentErrorHandler.HandleAndThrowBusinessLogicException(ex, TridentErrorConstants.ErrorNumber1300000001, ex.Message);
            }
        }

        /// <summary>
        /// Checks the activity validity.
        /// </summary>
        /// <param name="activity">The activity.</param>
        /// <returns></returns>
        private bool CheckActivityValidityForNormalUser(Activity activity)
        {
            bool validActivity = false;
            if (!activity.IsDeleted
                && activity.IsWorkflow
                && this.currentUser != null
                && this.systemUserObject != null
                && !activity.Owner.Equals(this.currentUser)
                && !activity.Owner.Equals(this.systemUserObject)
                && activity.Security.Rights.AuthorWorkflow.Check(TridentAuthentication.LoggedInUser))
            {
                validActivity = true;
            }

            return validActivity;
        }

        /// <summary>
        /// Fetches the base activity sequence.
        /// </summary>
        /// <param name="actSeq">The act seq.</param>
        /// <returns>The base sequence.</returns>
        private ActivitySequence FetchBaseActivitySequence(ActivitySequence actSeq)
        {
            ActivitySequence parentSeq = null;
            if (actSeq != null)
            {
                if (null == actSeq.Parent)
                {
                    parentSeq = actSeq;
                }
                else
                {
                    parentSeq = this.FetchBaseActivitySequence(actSeq.Parent);
                }
            }

            return parentSeq;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        private User GetSystemUser()
        {
            User systemUser = null;
            try
            {
                systemUser = User.Load(RegistryManagerService.SystemUserName, this.registryConnection);
            }
            catch (RecordNotFoundException ex)
            {
                TridentErrorHandler.HandleUIException(ex);
            }

            return systemUser;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="source"></param>
        /// <param name="destination"></param>
        private void CascadeMoveActivities(Namespace source, Namespace destination)
        {
            RegistryManagerService.MoveActivities(source, destination);
            foreach (Namespace childCategory in source.Children)
            {
                this.CascadeMoveActivities(childCategory, destination);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="source"></param>
        /// <param name="destination"></param>
        private static void MoveActivities(Namespace source, Namespace destination)
        {
            // Move the activities from the source category to the destination category.
            foreach (Activity activity in source.Activitys)
            {
                activity.Namespaces.Clear();
                destination.Activitys.Add(activity);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        private Namespace CreateCategoryFromModel(CategoryViewModel model)
        {
            Namespace createdNamespace = null;
            try
            {
                if (!string.IsNullOrEmpty(model.Name) && !string.IsNullOrEmpty(model.Name.Trim()))
                {
                    Namespace newNamespace = Namespace.Create(model.Name.Trim(), this.registryConnection);
                    createdNamespace = this.UpdateNamespace(model, newNamespace);
                }
            }
            catch (RecordNotFoundException ex)
            {
                TridentErrorHandler.HandleUIException(ex);
            }

            return createdNamespace;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="model"></param>
        /// <param name="nameSpace"></param>
        /// <returns></returns>
        private Namespace UpdateNamespace(CategoryViewModel model, Namespace nameSpace)
        {
            try
            {
                if (model.Parent != null)
                {
                    Namespace parent = Namespace.Load(model.Parent.Id, this.registryConnection);
                    nameSpace.Parent = parent;
                }

                nameSpace.Description = string.IsNullOrEmpty(model.Description) ? string.Empty : model.Description.Trim();
                nameSpace.Name = model.Name.Trim();
                nameSpace.Label = nameSpace.Name;
                nameSpace.IsEditable = model.IsEditable;

                nameSpace.Save();
                if (!string.IsNullOrEmpty(model.IconPath) && File.Exists(model.IconPath))
                {
                    Image img = null;
                    try
                    {
                        img = Image.FromFile(model.IconPath);
                    }
                    catch
                    {
                        // Some icon file formats throw an exception. Need to use the icon class instead. 
                        Icon icon = new Icon(model.IconPath);
                        img = icon.ToBitmap();
                    }
                    if (img != null)
                    {
                        try
                        {
                            this.registryConnection.AutoSave = true;
                            img.Tag = System.IO.Path.GetFileName(model.IconPath);
                            nameSpace.Icon = img;
                        }
                        finally
                        {
                            this.registryConnection.AutoSave = false;
                        }
                    }
                }
                else if (null == model.Icon)
                {
                    try
                    {
                        this.registryConnection.AutoSave = true;
                        nameSpace.Icon = null;
                    }
                    finally
                    {
                        this.registryConnection.AutoSave = false;
                    }
                }
            }
            catch (RecordNotFoundException ex)
            {
                TridentErrorHandler.HandleAndThrowBusinessLogicException(ex, TridentErrorConstants.ErrorNumber1000000024, ex.Message);
            }
            catch (Exception ex)
            {
                TridentErrorHandler.ProcessKnownExceptionsInBusinessLogic(ex);
                TridentErrorHandler.HandleAndThrowBusinessLogicException(ex, TridentErrorConstants.ErrorNumber1000000025, ex.Message);
            }

            return nameSpace;
        }

        /// <summary>
        /// Edit the node details.
        /// </summary>
        /// <param name="model">The model containing the node details.</param>
        /// <returns>The edited node.</returns>
        private Machine EditNode(NodeViewModel model)
        {
            Machine nodeToEdit = Machine.Load(model.Id, this.registryConnection);
            nodeToEdit.Availability = model.ExecutorAvailability;
            nodeToEdit.Description = model.Description;
            nodeToEdit.MaxConcurrentJobs = model.MaxConcurrentJobs;
            nodeToEdit.ClusterUser = model.ClusterUser;
            nodeToEdit.ClusterPassword = model.ClusterPassword;
            nodeToEdit.ComputeInstalledDirectory = model.InstalledDir;
            nodeToEdit.Save();
            return nodeToEdit;
        }

        /// <summary>
        /// Delete the node specified.
        /// </summary>
        /// <param name="nodeId">Guid of the node to delete.</param>
        private void SoftDeleteNode(Guid nodeId)
        {
            Machine nodeToDelete = Machine.Load(nodeId, this.registryConnection);

            // Retrieve the schedules.
            JobCollection<Machine> jobs = nodeToDelete.Jobs;

            // Cancel the schedules associated with the node. The scheduler service cleans it.
            foreach (Job job in jobs)
            {
                foreach (JobSchedule schedule in job.Schedules)
                {
                    schedule.Status = ScheduleStatus.Cancelled;
                    schedule.Save();
                }
            }

            // Set the flag.
            nodeToDelete.IsDeleted = true;
            nodeToDelete.Save();
        }

        /// <summary>
        /// Updates the activity.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <param name="activity">The activity.</param>
        /// <returns>Status of update</returns>
        private Activity UpdateActivity(ActivityViewModel model, Activity activity)
        {
            try
            {
                activity.Name = model.Name.Trim();
                string label = activity.Name;
                if (!string.IsNullOrEmpty(model.Label) && !string.IsNullOrEmpty(model.Label.Trim()))
                {
                    label = model.Label.Trim();
                }

                activity.Label = label;
                string author = string.Empty;
                if (!string.IsNullOrEmpty(model.Author) && !string.IsNullOrEmpty(model.Author.Trim()))
                {
                    author = model.Author.Trim();
                }

                activity.Author = author;
                activity.Description = string.IsNullOrEmpty(model.Description) ? string.Empty : model.Description.Trim();
                activity.Keywords = model.Keywords;
                CategoryViewModel parentModel = model.Parent as CategoryViewModel;
                if (model.Parent != null)
                {
                    Namespace parent = Namespace.Load(model.Parent.Id, this.registryConnection);
                    if (parent != null)
                    {
                        activity.Namespaces.Clear();
                        parent.Activitys.Add(activity);
                    }
                }

                foreach (ParameterModel inputModel in model.InputParameters)
                {
                    ActivityParameter activityParameter = activity.ActivityParameters.FirstOrDefault(item => (item as IObject).ID.Equals(inputModel.Id));
                    if (activityParameter != null)
                    {
                        bool needsSave = false;
                        if (activityParameter.Required != inputModel.Required)
                        {
                            activityParameter.Required = inputModel.Required;
                            needsSave = true;
                        }

                        if ((string.IsNullOrEmpty(activityParameter.DefaultValue) && !string.IsNullOrEmpty(inputModel.DefaultValue)) ||
                            (!string.IsNullOrEmpty(activityParameter.DefaultValue) && string.IsNullOrEmpty(inputModel.DefaultValue)) ||
                            (!string.IsNullOrEmpty(activityParameter.DefaultValue) && !string.IsNullOrEmpty(inputModel.DefaultValue) &&
                            !activityParameter.DefaultValue.Equals(inputModel.DefaultValue, StringComparison.CurrentCulture)))
                        {
                            activityParameter.DefaultValue = inputModel.DefaultValue;
                            needsSave = true;
                        }

                        if (needsSave)
                        {
                            activityParameter.Save();
                        }
                    }
                }

                activity.Save();
                if (!string.IsNullOrEmpty(model.IconPath) && File.Exists(model.IconPath))
                {
                    Image img = null;
                    try
                    {
                        img = Image.FromFile(model.IconPath);
                    }
                    catch
                    {
                        // Some icon file formats throw an exception. Need to use the icon class instead. 
                        Icon icon = new Icon(model.IconPath);
                        img = icon.ToBitmap();
                    }
                    if (img != null)
                    {
                        try
                        {
                            this.registryConnection.AutoSave = true;
                            img.Tag = System.IO.Path.GetFileName(model.IconPath);
                            activity.Icon = img;
                        }
                        finally
                        {
                            this.registryConnection.AutoSave = false;
                        }
                    }
                }
                else if (null == model.Icon)
                {
                    try
                    {
                        this.registryConnection.AutoSave = true;
                        activity.Icon = null;
                    }
                    finally
                    {
                        this.registryConnection.AutoSave = false;
                    }
                }
            }
            catch (RecordNotFoundException ex)
            {
                TridentErrorHandler.HandleAndThrowBusinessLogicException(ex, TridentErrorConstants.ErrorNumber1000000041, ex.Message);
            }
            catch (Exception ex)
            {
                TridentErrorHandler.ProcessKnownExceptionsInBusinessLogic(ex);
                TridentErrorHandler.HandleAndThrowBusinessLogicException(ex, TridentErrorConstants.ErrorNumber1000000042, ex.Message);
            }

            activity.Refresh();
            return activity;
        }

        /// <summary>
        /// Fetches the activity from model.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns>The registry activity</returns>
        private Activity FetchActivityFromModel(ActivityViewModel model)
        {
            Activity activity = null;
            if (this.registryConnection != null && model != null)
            {
                try
                {
                    if (!model.Id.Equals(Guid.Empty))
                    {
                        activity = Activity.Load(model.Id, this.registryConnection);
                    }
                }
                catch (RecordNotFoundException)
                {
                    throw new TridentCustomException(ManagementStudio.ErrorActivityNotFound);
                }
                catch (Exception ex)
                {
                    TridentErrorHandler.ProcessKnownExceptionsInBusinessLogic(ex);
                }
            }

            return activity;
        }

        /// <summary>
        /// Edits and saves the type initializer.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns>The saved type intializer</returns>
        private TypeInitializer EditTypeInitializer(TypeInitializerModel model)
        {
            TypeInitializer savedTypeInitializer = TypeInitializer.Load(model.Id, this.registryConnection);
            if (savedTypeInitializer != null && !savedTypeInitializer.IsDeleted)
            {
                savedTypeInitializer.Author = model.Author;
                savedTypeInitializer.Save();
            }

            return savedTypeInitializer;
        }

        /// <summary>
        /// Delete the type initializer.
        /// </summary>
        /// <param name="model">
        /// The model representing the type intializer to delete.
        /// </param>
        /// <returns>
        /// Status of the type intializer delete.
        /// </returns>
        private bool TypeInitializerDelete(TypeInitializerModel model)
        {
            bool deleteSuccess = true;
            if (!this.ValidateTypeInitializerDelete(model))
            {
                TridentErrorHandler.HandleAndThrowBusinessLogicException(
                    new InvalidOperationException(ManagementStudioResourceManager.GetString("TypeInitializerInUse")),
                    TridentErrorConstants.ErrorNumber1000000053,
                    ManagementStudioResourceManager.GetString("TypeInitializerInUse"));
            }

            try
            {
                TypeInitializer savedTypeInitializer = TypeInitializer.Load(model.Id, this.registryConnection);
                if (savedTypeInitializer != null)
                {
                    savedTypeInitializer.IsDeleted = true;
                    savedTypeInitializer.Save();
                    TypeProviderHelper.RefreshTypeInitializersCache();
                }
                else
                {
                    deleteSuccess = false;
                }
            }
            catch (ObjectInUseException ex)
            {
                deleteSuccess = false;
                TridentErrorHandler.HandleAndThrowBusinessLogicException(ex,
                    TridentErrorConstants.ErrorNumber1000000050,
                    ManagementStudioResourceManager.GetString("TypeInitializerDeleteError"));
            }
            catch (RecordNotFoundException ex)
            {
                deleteSuccess = false;
                TridentErrorHandler.HandleAndThrowBusinessLogicException(ex,
                    TridentErrorConstants.ErrorNumber1000000051,
                    ManagementStudioResourceManager.GetString("TypeInitializerDeleteError"));
            }
            catch (Exception ex)
            {
                deleteSuccess = false;
                TridentErrorHandler.ProcessKnownExceptionsInBusinessLogic(ex);
                TridentErrorHandler.HandleAndThrowBusinessLogicException(ex,
                    TridentErrorConstants.ErrorNumber1000000052,
                    ManagementStudioResourceManager.GetString("TypeInitializerDeleteError"));
            }

            return deleteSuccess;
        }

        /// <summary>
        /// Validates if deleting type intializer is a clean operation.
        /// </summary>
        /// <param name="model">
        /// Type intializer to be deleted.
        /// </param>
        /// <returns>
        /// True if valid, false otherwise.
        /// </returns>
        private bool ValidateTypeInitializerDelete(TypeInitializerModel model)
        {
            bool validDelete = true;
            bool containsRestrictedWfs = false;
            if (null == model)
            {
                validDelete = false;
            }
            else
            {
                List<WorkflowViewModel> workflows = this.FetchTypeInitializerRelatedWorkflows(model, out containsRestrictedWfs);
                if (workflows.Count > 0 || containsRestrictedWfs)
                {
                    validDelete = false;
                }
            }

            return validDelete;
        }

        /// <summary>
        /// Fetches the type initializer related workflows.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns>List of related workflows.</returns>
        private List<WorkflowViewModel> FetchTypeInitializerRelatedWorkflows(TypeInitializerModel model, out bool containsRestrictedWfs)
        {
            containsRestrictedWfs = false;
            List<WorkflowViewModel> relatedWorkflows = new List<WorkflowViewModel>();
            if (model != null && model.CompleteTypeInitializerModel)
            {
                TypeInitializer typeInitializer = TypeInitializer.Load(model.Id, this.registryConnection);
                if (typeInitializer != null && !typeInitializer.IsDeleted)
                {
                    string supportingType = typeInitializer.RelatedType.TypeName;

                    try
                    {
                        ActivityParameter.ISearch searchQuery = ActivityParameter.ISearch.Create();
                        searchQuery.Query = ActivityParameter.ISearch.Type(StringField.Condition.Equals, supportingType);
                        List<ActivityParameter> parameters = ActivityParameter.Search(searchQuery, this.registryConnection);
                        foreach (ActivityParameter parameter in parameters)
                        {
                            bool restrictedWfs = false;
                            relatedWorkflows.AddRange(this.FetchRelatedWorkflowsByActivity(parameter.Activity, true, out restrictedWfs));
                            if (!containsRestrictedWfs)
                            {
                                containsRestrictedWfs = restrictedWfs;
                            }
                        }
                    }
                    catch (RecordNotFoundException)
                    {
                    }

                    relatedWorkflows = relatedWorkflows.Distinct(new WorkflowModelComparer()).ToList();
                }
            }

            return relatedWorkflows;
        }

        /// <summary>
        /// Fetches the type initializer related workflows.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns>List of related workflows.</returns>
        private List<WorkflowViewModel> FetchTypeInitializerRelatedWorkflows(TypeInitializerModel model)
        {
            bool containsRestrictedWfs = false;
            return this.FetchTypeInitializerRelatedWorkflows(model, out containsRestrictedWfs);
        }

        /// <summary>
        /// Fetches the related workflows by activity.
        /// </summary>
        /// <param name="activity">The activity.</param>
        /// <returns></returns>
        private Collection<WorkflowViewModel> FetchRelatedWorkflowsByActivity(Activity activity, bool allowDeletedWorkflows)
        {
            bool containsRestrictedWfs = false;
            return this.FetchRelatedWorkflowsByActivity(activity, allowDeletedWorkflows, out containsRestrictedWfs);
        }

        /// <summary>
        /// Fetches the related workflows by activity.
        /// </summary>
        /// <param name="activity">The activity.</param>
        /// <returns></returns>
        private Collection<WorkflowViewModel> FetchRelatedWorkflowsByActivity(Activity activity, bool allowDeletedWorkflows, out bool containsRestrictedWfs)
        {
            containsRestrictedWfs = false;
            Collection<WorkflowViewModel> relatedWorkflows = new Collection<WorkflowViewModel>();
            if (null != activity)
            {
                Collection<ActivitySequence> baseSequences = new Collection<ActivitySequence>();

                foreach (ActivitySequence actSeq in activity.ActivitySequences)
                {
                    ActivitySequence baseSequence = this.FetchBaseActivitySequence(actSeq);
                    try
                    {
                        if (baseSequence != null && baseSequence.IsBase
                            && (allowDeletedWorkflows || !baseSequence.Activity.IsDeleted))
                        {
                            baseSequences.Add(baseSequence);
                        }
                    }
                    catch (System.Security.SecurityException)
                    {
                        // Ignore: User does not have permission for the Worklfow.
                    }
                }

                foreach (ActivitySequence wfSeq in baseSequences.Distinct(new ActivitySequenceComparer()))
                {
                    try
                    {
                        relatedWorkflows.Add(new WorkflowViewModel(wfSeq.Activity));
                    }
                    catch (System.Security.SecurityException)
                    {
                        // Ignore: User does not have permission for the Worklfow.
                        containsRestrictedWfs = true;
                    }
                }
            }

            return relatedWorkflows;
        }

        /// <summary>
        /// Create the activity sequences.
        /// </summary>
        /// <param name="oldVersion">Old workflow instance.</param>
        /// <param name="newVersion">New workflow instance.</param>
        private void CreateActivitySequences(Activity oldVersion, Activity newVersion)
        {
            Dictionary<string, ActivitySequence> newSequenceMap = new Dictionary<string, ActivitySequence>();
            Dictionary<string, ActivitySequence> oldSequenceMap = new Dictionary<string, ActivitySequence>();

            ActivitySequence.CopyHelper copyHelper = new ActivitySequence.CopyHelper(null, newVersion);
            ActivitySequence baseSequence = copyHelper.CopyTo(this.registryConnection, oldVersion.BaseSequence) as ActivitySequence;
            oldVersion.BaseSequence.Children.GetEnumerator();
            foreach (ActivitySequence sequence in oldVersion.BaseSequence.Children)
            {
                this.CopyActivitySequences(baseSequence, sequence, newSequenceMap, oldSequenceMap);
            }

            // Parameter Bindings have to be created after all the sequences are created because a 
            // parameter can be bound to another parameter from an sequence which has not been iterated through yet.
            AssignParameterBindings(newSequenceMap, oldSequenceMap);
        }

        /// <summary>
        /// Create a copy of the activity sequences and assign to the new parent.
        /// </summary>
        /// <param name="parent">The parent assembly sequence.</param>
        /// <param name="sequenceToCopy">The original sequence.</param>
        private void CopyActivitySequences(ActivitySequence parent,
            ActivitySequence sequenceToCopy,
            Dictionary<string, ActivitySequence> newSequenceMap,
            Dictionary<string, ActivitySequence> oldSequenceMap)
        {
            ActivitySequence.CopyHelper copyHelper = new ActivitySequence.CopyHelper(parent, sequenceToCopy.Activity);
            ActivitySequence newActivitySequence = copyHelper.CopyTo(this.registryConnection, sequenceToCopy) as ActivitySequence;
            newSequenceMap.Add(newActivitySequence.Name, newActivitySequence);
            oldSequenceMap.Add(sequenceToCopy.Name, sequenceToCopy);
            this.CopyParameterAssignments(newActivitySequence, sequenceToCopy);
            foreach (ActivitySequence child in sequenceToCopy.Children)
            {
                CopyActivitySequences(newActivitySequence, child, newSequenceMap, oldSequenceMap);
            }
        }

        /// <summary>
        /// Create copies of the parameter assignments of the activity sequence.
        /// </summary>
        /// <param name="destination">The destination sequence.</param>
        /// <param name="source">The source sequence.</param>
        private void CopyParameterAssignments(ActivitySequence destination, ActivitySequence source)
        {
            foreach (ParameterAssignment parameterAssignment in source.ParameterAssignments)
            {
                ParameterAssignment.CopyHelper copyHelper =
                    new ParameterAssignment.CopyHelper(parameterAssignment.ActivityParameter, destination, null);
                ParameterAssignment newParamAssignment =
                    copyHelper.CopyTo(this.registryConnection, parameterAssignment) as ParameterAssignment;
            }
        }

        /// <summary>
        /// Assign bindings to parameter assignments.
        /// </summary>
        /// <param name="newSequenceMap">The dictionary containing all the new sequences.</param>
        /// <param name="oldSequenceMap">The dictionary containing all the old sequences.</param>
        private static void AssignParameterBindings(Dictionary<string, ActivitySequence> newSequenceMap,
            Dictionary<string, ActivitySequence> oldSequenceMap)
        {
            foreach (ActivitySequence oldActivitySequence in oldSequenceMap.Values)
            {
                // Get all the bound parameters from the assignment.
                IEnumerable<ParameterAssignment> boundParameters =
                    oldActivitySequence.ParameterAssignments.Where(p => p.BoundTo != null) as IEnumerable<ParameterAssignment>;
                ActivitySequence newSequence = newSequenceMap[oldActivitySequence.Name];
                foreach (ParameterAssignment paramAssignment in boundParameters)
                {
                    // Get the required parameter from the new sequence.
                    ParameterAssignment newParameterAssignment =
                        newSequence.ParameterAssignments.FirstOrDefault(p => p.ActivityParameter.Name.Equals(paramAssignment.ActivityParameter.Name)
                            && p.ActivityParameter.Direction == paramAssignment.ActivityParameter.Direction);

                    ParameterAssignment boundTo = paramAssignment.BoundTo;

                    // Get the sequence to which it is bound to.
                    ActivitySequence newBoundToSequence = newSequenceMap[boundTo.Instance.Name];
                    newSequence.ParameterAssignments.Refresh();

                    // Get the parameter assignment to which it is bound to.
                    ParameterAssignment newBoundTo =
                        newBoundToSequence.ParameterAssignments.FirstOrDefault(p => p.ActivityParameter.Name.Equals(boundTo.ActivityParameter.Name)
                          && p.ActivityParameter.Direction == boundTo.ActivityParameter.Direction);
                    newParameterAssignment.BoundTo = newBoundTo;
                    newParameterAssignment.Save();
                }
            }
        }


        /// <summary>
        /// Check if the activity is referenced if a workflow.
        /// </summary>
        /// <param name="activity">The activity.</param>
        /// <returns>True if the activity is referenced in a workflow.False otherwise.</returns>
        private static bool IsActivityReferencedInWorkflow(Activity activity)
        {
            return (activity.ActivitySequences.Count != 0);
        }

        /// <summary>
        /// Deletes the activity and its parameters
        /// </summary>
        /// <param name="activityToDelete">Activity</param>
        private void DeleteActivity(Activity activityToDelete)
        {
            foreach (ActivityParameter parameter in activityToDelete.ActivityParameters)
            {
                parameter.Delete();
            }
            activityToDelete.AssemblyPackages.Clear();
            activityToDelete.Delete();
        }

        /// <summary>
        /// Deletes the Activity from the registry.
        /// If the activity has not been refered in any workflow Delete the activity Permanently(Hard delete).
        /// If the activity has been refered in any deleted workflow Set its Isdeleted flag to true.
        /// </summary>
        /// <param name="model">ActivityViewModel</param>
        public void DeleteActivity(ActivityViewModel model)
        {
            try
            {
                Collection<WorkflowViewModel> relateWorkflows = this.FetchRelatedWorkflows(model);

                // Check is there any related workflows, and throw the error to the user if it has any.
                if (relateWorkflows != null && relateWorkflows.Count > 0)
                {
                    throw new TridentCustomException(ManagementStudioResourceManager.GetString("ActivityCannotDeleteWarning"));
                }

                Activity activity = this.FetchActivityFromModel(model);
                activity.IsDeleted = true;
                activity.Save();
            }
            catch (TridentCustomException)
            {
                throw;
            }
            catch (Exception ex)
            {
                TridentErrorHandler.ProcessKnownExceptionsInBusinessLogic(ex);
                TridentErrorHandler.HandleAndThrowBusinessLogicException(ex, TridentErrorConstants.ErrorNumber1000000054, ManagementStudioResourceManager.GetString("ErrorDeleteActivity"));
            }
        }

        #endregion

        #region External Data Reference Members

        /// <summary>
        /// Gets all data reference providers.
        /// </summary>
        /// <returns></returns>
        public Collection<DataReferenceProviderModel> GetAllDataReferenceProviders()
        {
            Collection<DataReferenceProviderModel> providers = new Collection<DataReferenceProviderModel>();

            try
            {
                DataReferenceProvider.LoadAll(this.RegistryConnection)
                    .ForEach(provider => providers.Add(new DataReferenceProviderModel(provider)));
            }
            catch (RecordNotFoundException ex)
            {
                TridentErrorHandler.HandleUIException(ex);
            }
            catch (Exception ex)
            {
                TridentErrorHandler.ProcessKnownExceptionsInBusinessLogic(ex);
                TridentErrorHandler.HandleAndThrowBusinessLogicException(ex, TridentErrorConstants.ErrorNumber1400000005, ex.Message);
            }

            return providers;
        }

        /// <summary>
        /// Saves the data reference provider.
        /// </summary>
        /// <param name="providerModel">The provider model.</param>
        /// <returns></returns>
        public DataReferenceProvider SaveDataReferenceProvider(DataReferenceProviderModel providerModel)
        {
            if (providerModel == null)
            {
                throw new ArgumentNullException("providerModel");
            }

            try
            {
                return this.EditDataReferenceProvider(providerModel);
            }
            catch (RecordNotFoundException ex)
            {
                TridentErrorHandler.HandleAndThrowBusinessLogicException(ex,
                     TridentErrorConstants.ErrorNumber1400000006,
                     ManagementStudioResourceManager.GetString("DataReferenceProviderSaveError"));
            }
            catch (Exception ex)
            {
                TridentErrorHandler.ProcessKnownExceptionsInBusinessLogic(ex);
                TridentErrorHandler.HandleAndThrowBusinessLogicException(ex,
                    TridentErrorConstants.ErrorNumber1400000008,
                    ManagementStudioResourceManager.GetString("DataReferenceProviderSaveError"));
            }

            return null;
        }

        /// <summary>
        /// Edits the data reference provider.
        /// </summary>
        /// <param name="providerModel">The provider model.</param>
        /// <returns></returns>
        private DataReferenceProvider EditDataReferenceProvider(DataReferenceProviderModel providerModel)
        {
            DataReferenceProvider referenceProvider;
            if (providerModel.Id != null && !providerModel.Id.Equals(Guid.Empty))
            {
                referenceProvider = DataReferenceProvider.Load(providerModel.Id, this.registryConnection);
            }
            else
            {
                referenceProvider = DataReferenceProvider.Create(providerModel.Name, this.registryConnection);
            }

            if (referenceProvider != null)
            {
                referenceProvider.Name = providerModel.Name;

                if (!string.IsNullOrEmpty(providerModel.Description))
                {
                    referenceProvider.Description = providerModel.Description.Trim();
                }

                referenceProvider.Save();
            }

            return referenceProvider;
        }

        /// <summary>
        /// Saves the data reference store.
        /// </summary>
        /// <param name="storeModel">The store model.</param>
        /// <returns></returns>
        public DataReferenceStore SaveDataReferenceStore(DataReferenceStoreModel storeModel)
        {
            if (storeModel == null)
            {
                throw new ArgumentNullException("storeModel");
            }

            try
            {
                return this.EditDataReferenceStore(storeModel);
            }
            catch (RecordNotFoundException ex)
            {
                TridentErrorHandler.HandleAndThrowBusinessLogicException(ex,
                     TridentErrorConstants.ErrorNumber1400000009,
                     ManagementStudioResourceManager.GetString("DataReferenceStoreSaveError"));
            }
            catch (Exception ex)
            {
                TridentErrorHandler.ProcessKnownExceptionsInBusinessLogic(ex);
                TridentErrorHandler.HandleAndThrowBusinessLogicException(ex,
                    TridentErrorConstants.ErrorNumber1400000010,
                    ManagementStudioResourceManager.GetString("DataReferenceStoreSaveError"));
            }

            return null;
        }

        /// <summary>
        /// Edits the data reference store.
        /// </summary>
        /// <param name="storeModel">The store model.</param>
        /// <returns></returns>
        private DataReferenceStore EditDataReferenceStore(DataReferenceStoreModel storeModel)
        {
            DataReferenceStore referenceStore;
            if (storeModel.Id != null && !storeModel.Id.Equals(Guid.Empty))
            {
                referenceStore = DataReferenceStore.Load(storeModel.Id, this.registryConnection);
            }
            else
            {
                referenceStore = DataReferenceStore.Create(storeModel.Name, this.registryConnection);
            }

            if (referenceStore != null)
            {
                referenceStore.Name = storeModel.Name.Trim();

                if (!string.IsNullOrEmpty(storeModel.Description))
                {
                    referenceStore.Description = storeModel.Description.Trim();
                }

                referenceStore.DataProviderParameters = storeModel.Parameters;

                referenceStore.Provider = DataReferenceProvider.Load(storeModel.Parent.Id, this.registryConnection);

                referenceStore.Save();
            }

            return referenceStore;
        }

        /// <summary>
        /// Deletes the data reference store.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns></returns>
        public bool DeleteDataReferenceStore(DataReferenceStoreModel model)
        {
            if (null == model)
            {
                throw new ArgumentNullException("model");
            }

            return this.DataReferenceStoreDelete(model);
        }

        /// <summary>
        /// Deletes the data reference provider.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns></returns>
        public bool DeleteDataReferenceProvider(DataReferenceProviderModel model)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Imports the data reference provider.
        /// </summary>
        /// <param name="assemblyPath">The assembly path.</param>
        /// <returns></returns>
        public bool? ImportDataReferenceProvider(string assemblyPath)
        {
            bool? importSuccess = true;
            if (this.registryConnection != null)
            {
                ExternalRegistryProxy externalRegistryHelper = new ExternalRegistryProxy(this.registryConnection, assemblyPath);
                importSuccess = externalRegistryHelper.Execute();
            }

            return importSuccess;
        }

        /// <summary>
        /// Delete the type initializer.
        /// </summary>
        /// <param name="model">
        /// The model representing the type intializer to delete.
        /// </param>
        /// <returns>
        /// Status of the type intializer delete.
        /// </returns>
        private bool DataReferenceStoreDelete(DataReferenceStoreModel model)
        {
            bool deleteSuccess = true;
            if (!this.ValidateDataReferenceStoreDelete(model))
            {
                TridentErrorHandler.HandleAndThrowBusinessLogicException(
                    new InvalidOperationException(ManagementStudioResourceManager.GetString("DataRefererenceStoreInUse")),
                    TridentErrorConstants.ErrorNumber1400000011,
                    ManagementStudioResourceManager.GetString("DataRefererenceStoreInUse"));
            }

            try
            {
                DataReferenceStore store = DataReferenceStore.Load(model.Id, this.registryConnection);
                if (store != null)
                {
                    store.Delete();
                }
                else
                {
                    deleteSuccess = false;
                }
            }
            catch (ObjectInUseException ex)
            {
                deleteSuccess = false;
                TridentErrorHandler.HandleAndThrowBusinessLogicException(ex,
                    TridentErrorConstants.ErrorNumber1400000012,
                    ManagementStudioResourceManager.GetString("DataReferenceStoreDeleteError"));
            }
            catch (RecordNotFoundException ex)
            {
                deleteSuccess = false;
                TridentErrorHandler.HandleAndThrowBusinessLogicException(ex,
                    TridentErrorConstants.ErrorNumber1400000013,
                    ManagementStudioResourceManager.GetString("DataReferenceStoreDeleteError"));
            }
            catch (Exception ex)
            {
                deleteSuccess = false;
                TridentErrorHandler.ProcessKnownExceptionsInBusinessLogic(ex);
                TridentErrorHandler.HandleAndThrowBusinessLogicException(ex,
                    TridentErrorConstants.ErrorNumber1400000014,
                    ManagementStudioResourceManager.GetString("DataReferenceStoreDeleteError"));
            }

            return deleteSuccess;
        }

        /// <summary>
        /// Validates the data reference store for deletion.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns></returns>
        private bool ValidateDataReferenceStoreDelete(DataReferenceStoreModel model)
        {
            bool validDelete = true;
            if (model == null)
            {
                validDelete = false;
            }
            else
            {
                DataReferenceStore store = DataReferenceStore.Load(model.Id, this.registryConnection);

                validDelete = true;
            }

            return validDelete;
        }

        #endregion

        #region GlobalSettings Members

        /// <summary>
        /// Gets the global setting.
        /// </summary>
        /// <returns></returns>
        public GlobalSetting GetGlobalSetting()
        {
            GlobalSetting settings = null;
            try
            {
                settings = GlobalSetting.LoadAll(this.registryConnection)[0];
            }
            catch (RecordNotFoundException)
            {
            }

            return settings;
        }

        /// <summary>
        /// Gets the data reference stores.
        /// </summary>
        /// <returns></returns>
        public Collection<DataReferenceStore> GetDataReferenceStores()
        {
            Collection<DataReferenceStore> dataReferenceStore = null;
            try
            {
                dataReferenceStore = new Collection<DataReferenceStore>(DataReferenceStore.LoadAll(this.registryConnection));
            }
            catch (RecordNotFoundException)
            {
            }
            catch (Exception ex)
            {
                TridentErrorHandler.ProcessKnownExceptionsInBusinessLogic(ex);
            }
            return dataReferenceStore;
        }

        /// <summary>
        /// Saves the global settings.
        /// </summary>
        /// <param name="dataProduct">The data product.</param>
        public void SaveGlobalSettings(string dataProduct)
        {
            GlobalSetting settings = this.GetGlobalSetting();
            bool isAutoSave = this.registryConnection.AutoSave;

            this.registryConnection.AutoSave = true;
            if (null == settings)
            {
                GlobalSetting.Initialize(dataProduct, this.registryConnection);
            }
            else
            {
                settings.Dataproduct = dataProduct;
            }

            this.registryConnection.AutoSave = isAutoSave;
        }

        #endregion


        /// <summary>
        /// Load the assemblies and the input parameters into the model.
        /// </summary>
        /// <param name="workflowModel">The workflow model.</param>
        /// <param name="libraryList">The library list.</param>
        /// <param name="parameterList">The parameter list.</param>
        public void GetWorkflowDetails(
            WorkflowCatalogViewModel workflowModel,
            Collection<WorkflowAssembly> libraryList,
            Collection<WorkflowParameter> parameterList)
        {
            try
            {
                Activity workflow = Activity.Load(workflowModel.Id, this.RegistryConnection);

                // This is to fetch the libraries for the blackbox worklfows.
                FetchLibrariesForBlackboxWorkflow(workflow, libraryList);

                ActivitySequence baseSequence = workflow.BaseSequence;
                if (baseSequence != null && baseSequence.Children.Count > 0)
                {
                    FetchActivityLibrary(baseSequence, libraryList, parameterList);
                }
            }
            catch (RecordNotFoundException ex)
            {
                TridentErrorHandler.HandleAndThrowBusinessLogicException(
                    ex,
                    TridentErrorConstants.ErrorNumber1000000073,
                    ManagementStudioResourceManager.GetString("ErrorRetrievingWorkflowDetails"));
            }
            catch (TridentCustomException)
            {
                throw;
            }
            catch (Exception ex)
            {
                TridentErrorHandler.HandleAndThrowBusinessLogicException(
                    ex,
                    TridentErrorConstants.ErrorNumber1000000073,
                    ManagementStudioResourceManager.GetString("ErrorRetrievingWorkflowDetails"));
            }
        }

        /// <summary>
        /// Fetches the libraries for blackbox workflow.
        ///     The properties of the blackbox workflows might contain 
        /// </summary>
        /// <param name="workflow">The workflow.</param>
        private static void FetchLibrariesForBlackboxWorkflow(Activity workflow, Collection<WorkflowAssembly> libraryList)
        {
            if (workflow.IsBlackbox)
            {
                FetchLibrary(workflow, libraryList);
            }
        }

        /// <summary>
        /// Fetches the activity library.
        /// </summary>
        /// <param name="rootActivitySequence">The root activity sequence.</param>
        private static void FetchActivityLibrary(
            ActivitySequence rootActivitySequence,
            Collection<WorkflowAssembly> libraryList,
            Collection<WorkflowParameter> parameterList)
        {
            foreach (ActivitySequence activitySequence in rootActivitySequence.Children)
            {
                FetchActivityLibrary(activitySequence, libraryList, parameterList);
            }

            Activity rootActivity = rootActivitySequence.Activity;
            FetchLibrary(rootActivity, libraryList);

            FetchParameters(rootActivitySequence, parameterList);
        }

        /// <summary>
        /// Fetches the parameters.
        /// </summary>
        /// <param name="rootActivitySequence">The root activity sequence.</param>
        /// <param name="parameterList">The parameter list.</param>
        private static void FetchParameters(ActivitySequence rootActivitySequence, Collection<WorkflowParameter> parameterList)
        {
            if (rootActivitySequence.ParameterAssignments.Count > 0)
            {
                IEnumerable<ParameterAssignment> requiredParams = rootActivitySequence.ParameterAssignments.Where(model => model.RequiredForWorkflow == true);
                foreach (ParameterAssignment parameter in requiredParams)
                {
                    WorkflowParameter workflowParameter = new WorkflowParameter(string.Format(CultureInfo.CurrentCulture, "{0}.{1}", rootActivitySequence.Name, parameter.ActivityParameter.Name), parameter.ActivityParameter.Type, parameter.ActivityParameter.DefaultValue);
                    parameterList.Add(workflowParameter);
                }
            }
        }

        /// <summary>
        /// Fetches the library from the activity.
        /// </summary>
        /// <param name="rootActivity">The root activity.</param>
        private static void FetchLibrary(Activity rootActivity, Collection<WorkflowAssembly> libraryList)
        {
            if (rootActivity.AssemblyPackages.Count > 0)
            {
                if (rootActivity.IsWorkflow)
                {
                    foreach (AssemblyPackage package in rootActivity.AssemblyPackages)
                    {
                        foreach (AssemblyImage img in package.AssemblyImages)
                        {
                            WorkflowAssembly wfList = libraryList.FirstOrDefault(assemblyName => assemblyName.Name.Equals(img.Filename));
                            if (wfList == null)
                            {
                                libraryList.Add(new WorkflowAssembly(img.Filename, img.Updated.When, img.Updated.User, img.Version.ToString(CultureInfo.CurrentCulture)));
                            }
                        }
                    }
                }
                else
                {
                    rootActivity.AssemblyPackages.GetEnumerator();
                    rootActivity.AssemblyPackages.Sort((p1, p2) => DateTime.Compare(p2.Updated.When, p1.Updated.When));
                    AssemblyPackage package = rootActivity.AssemblyPackages[0];

                    foreach (AssemblyImage img in package.AssemblyImages)
                    {
                        WorkflowAssembly wfList = libraryList.FirstOrDefault(assemblyName => assemblyName.Name.Equals(img.Filename));
                        if (wfList == null)
                        {
                            libraryList.Add(new WorkflowAssembly(img.Filename, img.Updated.When, img.Updated.User, img.Version.ToString(CultureInfo.CurrentCulture)));
                        }
                    }
                }
            }
        }
    }

    /// <summary>
    /// The comparer for an activity sequence.
    /// </summary>
    public class ActivitySequenceComparer : IEqualityComparer<ActivitySequence>
    {
        #region IEqualityComparer<ActivitySequence> Members

        /// <summary>
        /// Determines whether the specified objects are equal.
        /// </summary>
        /// <param name="x">The first object of type <paramref name="T"/> to compare.</param>
        /// <param name="y">The second object of type <paramref name="T"/> to compare.</param>
        /// <returns>
        /// true if the specified objects are equal; otherwise, false.
        /// </returns>
        public bool Equals(Microsoft.Research.DataLayer.ActivitySequence x, Microsoft.Research.DataLayer.ActivitySequence y)
        {
            return (x.Activity as IObject).ID.Equals((y.Activity as IObject).ID);
        }

        /// <summary>
        /// Returns a hash code for the specified object.
        /// </summary>
        /// <param name="obj">The <see cref="T:System.Object"/> for which a hash code is to be returned.</param>
        /// <returns>A hash code for the specified object.</returns>
        /// <exception cref="T:System.ArgumentNullException">The type of <paramref name="obj"/> is a reference type and <paramref name="obj"/> is null.</exception>
        public int GetHashCode(Microsoft.Research.DataLayer.ActivitySequence obj)
        {
            return (obj as IObject).ID.GetHashCode();
        }

        #endregion
    }
}
